#include <stdio.h>
#include <termios.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/types.h>
#include <dirent.h>

#include "usb_hotplug_check.h"
#include "uart_driver.h"
#include "common.h"


/**************************************************
 * 初始化usb串口
 *遍历usb串口设备 ，直到有可用设备
 * 返回值 ：成功 0 失败 ：-1
 * *************************************************/
int usb_serial_init_by_channel(uint8_t *channel)
{

	uint8_t i = 0x00;
	uint8_t usbserailnum = 0x00;

	uint8_t retrycnt = 0x00;
	DIR *pDir = NULL;
	struct dirent * pEnt = NULL;

	uint8_t modbusserialpath[64] = {0x00};
	uint8_t tmpfilepath[64] = {0x00};

	DEBUG_USB_SERIAL_PRINTF_LOGD("usb_serial_init_by_channel channel ：%d",*channel);
	if (*channel == 0xff)
	{
		usbserailnum = USB_SERIAL_AMOUNT;
	}
	else if ((*channel >= 0x00) &&(*channel <= 0x07))
	{
		usbserailnum =  *channel + 1;
		i = *channel;
	}
	else if ((*channel > 0x07) && (*channel < 0xff))
	{
		return -1;
	}

	for ( ;i < usbserailnum;i ++)
	{
		/*当前通道串口没被启用 :直接返回*/
		if (UsbSerialHotplugDetectionStru.usbserialchannelenableflag[i] ==0x00)
		{
			continue;
		}

		if (UsbSerialHotplugDetectionStru.usbserialdevicepath[i] == NULL)
		{
			continue;
		}

		DEBUG_USB_SERIAL_PRINTF_LOGD("%s",UsbSerialHotplugDetectionStru.usbserialdevicepath[i]);
		memset(tmpfilepath,0,strlen(tmpfilepath));

		sprintf(tmpfilepath,SYS_FILE_PATH);
		strcat(tmpfilepath,UsbSerialHotplugDetectionStru.usbserialdevicepath[i]);

		pDir = opendir(tmpfilepath);
		if (NULL == pDir)
		{

			strcat(tmpfilepath," open error!");
			DEBUG_USB_SERIAL_PRINTF_LOGD("%s",tmpfilepath);

			continue;
		}

		while(1)
		{
			pEnt = readdir(pDir);

			/*文件不为空 */
			if (pEnt != NULL)
			{
				if(strstr(pEnt->d_name,"ttyUSB") != NULL)
				{

					DEBUG_USB_SERIAL_PRINTF_LOGD("file %s exist",pEnt->d_name);

					memset(modbusserialpath,0,strlen(modbusserialpath));
					sprintf(modbusserialpath,"/dev/%s",pEnt->d_name);

					do{
						UsbSerialHotplugDetectionStru.usbserialfd[i] = init_serial(modbusserialpath, UsbSerialHotplugDetectionStru.usbserialbautrate[i]);
						if (UsbSerialHotplugDetectionStru.usbserialfd[i] < 0)
						{
							DEBUG_USB_SERIAL_PRINTF_LOGD("serial :%s init fail!\n",modbusserialpath);

							/*usb serial 初始化失败:当前状态下已经检测到usb串口未插入*/
							if (((UsbSerialHotplugDetectionStru.usbserialhotplugstats >> (i << 1)) & 0x00000003) == USB_SERIAL_N_INSERT)
							{
								UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (i << 1)) ;
							} else{
								UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (i << 1)) ;
								UsbSerialHotplugDetectionStru.usbserialhotplugstats |= USB_SERIAL_INIT_ERR << (i << 1);
							}
							deinit_serial(UsbSerialHotplugDetectionStru.usbserialfd[i]);
						}
						else
						{
							DEBUG_USB_SERIAL_PRINTF_LOGD("serial :%s init ok!\n",modbusserialpath);

							UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (i << 1)) ;
							UsbSerialHotplugDetectionStru.usbserialhotplugstats |= USB_SERIAL_INIT_OK << (i << 1);

							UsbSerialHotplugDetectionStru.usbseriachannellindex[i] = i;
							*channel = i;
							DEBUG_USB_SERIAL_PRINTF_LOGD("UsbSerialHotplugDetectionStru.usbserialhotplugstats :%d",UsbSerialHotplugDetectionStru.usbserialhotplugstats);

							return (UsbSerialHotplugDetectionStru.usbserialfd[i]);
						}
						retrycnt ++;
					}while(retrycnt < 0x03);
				}
			}
			else
			{
				break;
			}
		}
		closedir(pDir);
	}
	return (-1);
}

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
	 struct termios newtio,oldtio;
	 if  ( tcgetattr( fd,&oldtio)  !=  0) {
	  perror("SetupSerial 1");
	  return -1;
	 }
	 bzero( &newtio, sizeof( newtio ) );
	 newtio.c_cflag  |=  CLOCAL | CREAD; //CLOCAL:忽略modem控制�? CREAD：打开接受�?
	 newtio.c_cflag &= ~CSIZE; //字符长度掩码。取值为：CS5，CS6，CS7或CS8
 
	 switch( nBits )
	 {
	 case 7:
	  newtio.c_cflag |= CS7;
	  break;
	 case 8:
	  newtio.c_cflag |= CS8;
	  break;
	 }
 
	 switch( nEvent )
	 {
	 case 'O':
	  newtio.c_cflag |= PARENB; //允许输出产生奇偶信息以及输入到奇偶校�?
	  newtio.c_cflag |= PARODD;  //输入和输出是奇及校验
	  newtio.c_iflag |= (INPCK | ISTRIP); // INPACK:启用输入奇偶检测；ISTRIP：去掉第八位
	  break;
	 case 'E':
	  newtio.c_iflag |= (INPCK | ISTRIP);
	  newtio.c_cflag |= PARENB;
	  newtio.c_cflag &= ~PARODD;
	  break;
	 case 'N': 
	  newtio.c_cflag &= ~PARENB;
	  break;
	 }

	 switch( nSpeed )
	 {
	 case 2400:
	  cfsetispeed(&newtio, B2400);
	  cfsetospeed(&newtio, B2400);
	  break;
	 case 4800:
	  cfsetispeed(&newtio, B4800);
	  cfsetospeed(&newtio, B4800);
	  break;
	 case 9600:
	  cfsetispeed(&newtio, B9600);
	  cfsetospeed(&newtio, B9600);
	  break;
	  case 19200:
	  cfsetispeed(&newtio, B19200);
	  cfsetospeed(&newtio, B19200);
	  break;
	  
	 case 115200:
	  cfsetispeed(&newtio, B115200);
	  cfsetospeed(&newtio, B115200);
	  break;
	 case 460800:
	  cfsetispeed(&newtio, B460800);
	  cfsetospeed(&newtio, B460800);
	  break;
	 case 1500000:
	  cfsetispeed(&newtio,B1500000);
	  cfsetospeed(&newtio,B1500000);
	  break;

	 default:
	  cfsetispeed(&newtio, B9600);
	  cfsetospeed(&newtio, B9600);
	  break;
	 }
	 
	 if( nStop == 1 )
	  newtio.c_cflag &=  ~CSTOPB; //CSTOPB:设置两个停止位，而不是一�?
	 else if ( nStop == 2 )
	 newtio.c_cflag |=  CSTOPB;
	 
	 newtio.c_cc[VTIME]  = 0; //VTIME:非cannoical模式读时的延时，以十分之一秒位单位
	 newtio.c_cc[VMIN] = 0; //VMIN:非canonical模式读到最小字符数
	 tcflush(fd,TCIFLUSH); // 改变在所有写�?fd 引用的对象的输出都被传输后生效，所有已接受但未读入的输入都在改变发生前丢弃�?
	 if((tcsetattr(fd,TCSANOW,&newtio))!=0) //TCSANOW:改变立即发生
	 {
	  perror("com set error");
	  return -1;
	 }
	 printf("set done!\n\r");
	 return 0;
}

int init_serial(unsigned char * pfile,int nspeed)
{

	 int fd1 ;
	 int nset = 0;

	 fd1 = open( pfile, O_RDWR|O_NONBLOCK|O_NOCTTY);
	 if (fd1 == -1)
	 {
		printf("open  %s fail!!\n",pfile);		
		return -1;
	 }
	 printf("open  %s success!!\n",pfile);

	 nset = set_opt(fd1, nspeed, 8, 'N', 1);
	 if (nset == -1)
	{
		printf("SET  %s fail!!\n",pfile); 	 
		return -1;
	}
	 printf("SET  %s success!!\n",pfile);

 return fd1;
}

/*
*
*
*关闭串口
*
*
*
*
*
******/
int deinit_serial(int fd)
{
    close(fd);
    return 0;
}

/***
 * send data
 *
 *
 *
 * */
 int serial_send_data(int fd , unsigned char *sendbuff,int len)
{

    int  i = 0x00;

    if (fd <= 0)
    {
        return 0;
    }

	len = write(fd, sendbuff, len);
    return len;
}
/***
 * recv data
 *
 *
 *
 * */
int serial_recv_data(int fd , unsigned char *recvbuff,int len,uint32_t timeout)
{

	int i = 0x00;
	
    int maxfdp = 0x00;
	int recvlen = 0x00;

	uint32_t cnt = 0x00;
	
    fd_set rfds;
    struct timeval tv;

    tv.tv_sec = 10;
    tv.tv_usec = 0;

    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);

    maxfdp = fd + 1;    //描述符最大值加1
    if (select(maxfdp, &rfds, NULL, NULL, &tv) > 0) {
        if (FD_ISSET(fd, &rfds) > 0)
        {
        	/*有数据可读 :读出数据*/
            recvlen = read(fd, recvbuff, len);
			cnt += recvlen;
			
			/*等待40ms*/
			usleep(timeout);

			/*有数据可读 :读出数据*/
			recvlen = read(fd, recvbuff + recvlen, len);
			cnt += recvlen;
        }
    }
    return (cnt);
}
